import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios';
import { ElMessage } from 'element-plus';
import { getMessageInfo } from '@/utils/status';
import NProgress from 'nprogress'; // 需要安装 nprogress
import 'nprogress/nprogress.css';

declare module 'axios' {
	export interface AxiosRequestConfig {
		retryCount?: number;
	}
}
// 基础响应接口
interface BaseResponse<T = any> {
	code: number | string;
	message: string;
	data: T;
	status?: number | string;
}

// 请求队列接口
interface PendingRequest {
	url: string;
	cancel: Function;
}

// 请求队列
const pendingRequests: PendingRequest[] = [];

// 重试配置
const RETRY_COUNT = 3;
const RETRY_DELAY = 1000;

// 创建axios实例
const service: AxiosInstance = axios.create({
	baseURL: import.meta.env.VITE_APP_USE_MOCK
		? import.meta.env.VITE_APP_MOCK_BASEURL
		: import.meta.env.VITE_APP_API_BASEURL,
	timeout: 6000,
	// 允许跨域携带cookie
	withCredentials: true
});

// 移除待处理请求
const removePendingRequest = (config: InternalAxiosRequestConfig) => {
	const requestIndex = pendingRequests.findIndex((item) => item.url === config.url);
	if (requestIndex > -1) {
		const cancel = pendingRequests[requestIndex].cancel;
		cancel('取消重复请求');
		pendingRequests.splice(requestIndex, 1);
	}
};

// 请求拦截器
service.interceptors.request.use(
	(config: InternalAxiosRequestConfig) => {
		NProgress.start();

		// 检查是否存在重复请求，若存在则取消已发的请求
		removePendingRequest(config);

		// 添加取消令牌
		config.cancelToken = new axios.CancelToken((cancel) => {
			pendingRequests.push({
				url: config.url!,
				cancel
			});
		});

		// 这里可以添加token等通用请求头
		// config.headers['Authorization'] = `Bearer ${getToken()}`;

		return config;
	},
	(error: AxiosError) => {
		NProgress.done();
		return Promise.reject(error);
	}
);

// 响应拦截器
service.interceptors.response.use(
	(response: AxiosResponse) => {
		NProgress.done();
		removePendingRequest(response.config);
		return response;
	},
	async (error: any) => {
		NProgress.done();

		if (axios.isCancel(error)) {
			return Promise.reject(new Error('请求已取消'));
		}

		const config = error.config;

		// 实现请求重试
		if (config && config.retryCount < RETRY_COUNT) {
			config.retryCount = config.retryCount || 0;
			config.retryCount++;

			await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
			console.log(`重试请求: ${config.url}, 次数: ${config.retryCount}`);
			return service(config);
		}

		const { response } = error;
		const errorMessage = response ? getMessageInfo(response.status) : '网络异常,请稍后再试!';

		ElMessage({
			message: errorMessage,
			type: 'error'
		});

		return Promise.reject(response?.data || error);
	}
);

// 请求方法类型
type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';

// 统一的请求实例
const requestInstance = <T = any>(config: AxiosRequestConfig): Promise<T> => {
	return new Promise((resolve, reject) => {
		service
			.request<any, AxiosResponse<BaseResponse>>(config)
			.then((res: AxiosResponse<BaseResponse>) => {
				const data = res.data;
				if (data.code !== 0) {
					ElMessage.error(data.message);
					reject(data.message);
				} else {
					resolve(data.data as T);
				}
			})
			.catch((error) => {
				reject(error);
			});
	});
};

// 统一的请求函数
export function request<T = any, U = any>(
	method: RequestMethod,
	url: string,
	config: AxiosRequestConfig = {},
	data?: U
): Promise<T> {
	return requestInstance({
		...config,
		url,
		method,
		[method.toLowerCase() === 'get' ? 'params' : 'data']: data,
		retryCount: 0 // 初始化重试次数
	});
}

// 导出便捷请求方法
export const get = <T = any, U = any>(url: string, params?: U, config?: AxiosRequestConfig) =>
	request<T, U>('GET', url, config, params);

export const post = <T = any, U = any>(url: string, data: U, config?: AxiosRequestConfig) =>
	request<T, U>('POST', url, config, data);

export const put = <T = any, U = any>(url: string, data: U, config?: AxiosRequestConfig) =>
	request<T, U>('PUT', url, config, data);

export const del = <T = any, U = any>(url: string, data: U, config?: AxiosRequestConfig) =>
	request<T, U>('DELETE', url, config, data);

// 用于手动取消请求
export const cancelRequest = (url: string) => {
	const requestIndex = pendingRequests.findIndex((item) => item.url === url);
	if (requestIndex > -1) {
		const cancel = pendingRequests[requestIndex].cancel;
		cancel('手动取消请求');
		pendingRequests.splice(requestIndex, 1);
	}
};

// 取消所有请求
export const cancelAllRequests = () => {
	pendingRequests.forEach((item) => {
		item.cancel('取消所有请求');
	});
	pendingRequests.length = 0;
};

export default service;
